#pragma once

#include<cassert>
#include<string>
#include<vector>
#include<map>

#ifdef NDEBUG
    #define RELEASE_MODE
#endif

namespace Den{

struct Query;
struct QueryTypes
{
    //список поддерживаемых типов
    enum eTYPE{ eNULL, eBOOL, eINT, eDOUBLE, eSTRING, eVECTOR, eMAP };

       
    //размер максимального из поддерживаемых типов
    enum { eSIZE_BUFER = 32 };

    //для сокращения писанины
    typedef std::string                  Str;
    typedef std::vector<Query>         Vec;
    typedef std::map<const Str, Query> Map;

    //конвертирует тип в число
	template <class T>struct Type2Enum;
	template <>struct Type2Enum<bool>  { enum { eTYPE = eBOOL    }; };
	template <>struct Type2Enum<int>   { enum { eTYPE = eINT     }; };
	template <>struct Type2Enum<double>{ enum { eTYPE = eDOUBLE  }; };
	template <>struct Type2Enum<Str>   { enum { eTYPE = eSTRING  }; };
	template <>struct Type2Enum<Vec>   { enum { eTYPE = eVECTOR  }; };
	template <>struct Type2Enum<Map>   { enum { eTYPE = eMAP     }; };
};


struct Query:QueryTypes
{
   ~Query();
    Query();
    Query(const Query& src);

    template<class T>Query(const T& src)
        : mType( (eTYPE) Type2Enum<T>::eTYPE ) 
    { new(mBuf) T(src);   }

    Query(const char* src);

    Query& operator=(const Query& src);
    void Clear();

    template<class T> operator const T&()const
    {
        #ifndef RELEASE_MODE
            const bool INVALID_TYPE = Is<T>()==false;
            assert(!INVALID_TYPE);
        #endif
        return *((const T*)mBuf);
    }
    template<class T> operator T&()
    {
        #ifndef RELEASE_MODE
            const bool INVALID_TYPE = Is<T>()==false;
            assert(!INVALID_TYPE);
        #endif
        return *((T*)mBuf);
    }

    bool operator!=(const Query& src)const { return mType!=src.mType; }
    bool operator==(const Query& src)const { return mType==src.mType; }
    bool IsEmpty()const                      { return mType==eNULL;     }
    eTYPE GetType()const                     { return mType;            }

    template<class T> bool Is()const{ return mType==Type2Enum<T>::eTYPE; }

    bool Is_Primitive()const{ return Is<int>()||Is<Str>()||Is<double>()||Is<bool>(); }

    Query& operator[](const Str& key);
    const Query& operator[](const Str& key)const;

    Query& operator[](const size_t index);
    const Query& operator[](const size_t index)const;

    struct Iterator
    {
       ~Iterator();
        Iterator(Query* q=0l);

        //префиксная форма инкрементируется и возвращает значение
        Iterator& operator++();
        //постфиксная форма сперва делает копию. инкрементирует оригинал, а затем возвращает копию
        Iterator& operator++(int);
    
        const Query& operator*()const;
        Query& operator*();
        bool operator!=(const Iterator& it)const;
        bool operator==(const Iterator& it)const;
        bool IsEmpty()const;
    private:
        Query* mQuery;
    };

public:
#if 0
    //вывод структуры в текстовом виде
    const Query& operator>> (Str& dst)const;
    Query& operator>> (Str& dst);

    //воссоздание собственной структуры из текстового описания
    Query& operator<< (const Str& dst);
#endif
private:
    eTYPE mType;
    unsigned char mBuf[eSIZE_BUFER];
};


}//namespace Den

